package com.zlp.mymapviewproject.mymapview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import com.goodlib.goodlibView;
import net.xxhong.rosclient.R;
import java.util.ArrayList;
import org_rosjava.ros.android.android_tutorial_map_viewer.My_map;

public class MyMapView extends goodlibView {
    private MyBaseMapAndLines myBaseMapAndLines;
    private View originalPointView;
    private ArrayList<MyMapPointWithTitleView> mapPoints;
    private float firstScale;
    private boolean longPressTag = false;
    private float firstDownX;
    private float firstDownY;
    private long downTime;
    private MyMapViewOnLongClickListener mapOnLongClickListener;
    public float marked_mapX=0;
    public float marked_mapY=0;
    public MyMapView(Context context) {
        super(context);
        this.context = context;
        init();
    }
    public MyMapView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }
    public MyMapView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }
    private void init() {
        LayoutInflater.from(context).inflate(R.layout.view_mymap, this);
        myBaseMapAndLines = (MyBaseMapAndLines) this.findViewById(R.id.imageView);
        originalPointView = new MyMapPointWithTitleView(context);
        mapPoints = new ArrayList<>();
        this.setOnTouchListener(new MyTouchListener());
    }
    public void clearMapPoints() {
        for (int i = 0; i < mapPoints.size(); i++) {
            this.removeView(mapPoints.get(i));
        }
        this.mapPoints.clear();
    }
    public void addMapPoints_from_slam(ArrayList<MyMapPointWithTitleView> mapPoints_from_slam)
    {
        MyMapPointWithTitleView myMapPointWithTitleView=null;
        clearMapPoints();
        mapPoints=mapPoints_from_slam;
        for(int i=0;i<mapPoints.size();i++)
        {
            myMapPointWithTitleView=mapPoints.get(i);
            if(myMapPointWithTitleView!=null) {
                myMapPointWithTitleView.setFirstXShow((float) (myMapPointWithTitleView.getFirstX() * firstScale + originalPointView.getX()));
                myMapPointWithTitleView.setFirstYShow((float) (myMapPointWithTitleView.getFirstY() * firstScale + originalPointView.getY()));
                this.addView(myMapPointWithTitleView);
            }
        }
        if(myMapPointWithTitleView_tmp!=null)
        {
            this.addView(myMapPointWithTitleView_tmp);
        }
    }

    MyMapPointWithTitleView myMapPointWithTitleView_tmp=null;
    public void addMapPoint_tmp(MyMapPointWithTitleView myMapPointWithTitleView) {
        myMapPointWithTitleView_tmp=myMapPointWithTitleView;
        myMapPointWithTitleView_tmp.setFirstXShow((float) (myMapPointWithTitleView.getFirstX() * firstScale + originalPointView.getX()));
        myMapPointWithTitleView_tmp.setFirstYShow((float) (myMapPointWithTitleView.getFirstY() * firstScale + originalPointView.getY()));
        this.addView(myMapPointWithTitleView_tmp);
    }
    public void rmMapPoint_tmp() {
        if(myMapPointWithTitleView_tmp!=null) {
            this.removeView(myMapPointWithTitleView_tmp);
            myMapPointWithTitleView_tmp=null;
        }

    }

    MyMapPointWithTitleView_xuanfu_mark myMapPointWithTitleView_xuanfu_mark=null;
    public void addMapPoint_xuanfu_mark(MyMapPointWithTitleView_xuanfu_mark myMapPointWithTitleView) {
        myMapPointWithTitleView_xuanfu_mark=myMapPointWithTitleView;
        myMapPointWithTitleView_xuanfu_mark.setFirstXShow((float) (myMapPointWithTitleView.getFirstX() * firstScale + originalPointView.getX()));
        myMapPointWithTitleView_xuanfu_mark.setFirstYShow((float) (myMapPointWithTitleView.getFirstY() * firstScale + originalPointView.getY()));
        this.addView(myMapPointWithTitleView_xuanfu_mark);
    }
    public void rmMapPoint_xuanfu_mark() {
        if(myMapPointWithTitleView_xuanfu_mark!=null) {
            this.removeView(myMapPointWithTitleView_xuanfu_mark);
            myMapPointWithTitleView_xuanfu_mark=null;
        }

    }


    public void setMapState_at_first_get_map(Bitmap bitmap, int bitmapWith, int bitmapHeight) {
        myBaseMapAndLines.setImageBitmap(bitmap);
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics metric = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metric);
        int width = metric.widthPixels;
        int height = metric.heightPixels;
        float scale=(float) height / (float) bitmapHeight;
        this.firstScale = scale;
        Matrix matrix = new Matrix();
        originalPointView.setX((float) (originalPointView.getX() * scale));
        originalPointView.setY((float) (originalPointView.getY() * scale));
        float scale_With=(float) width / (float) bitmapWith;
        matrix.postScale(scale_With, scale_With, 0, bitmapHeight/scale);
        myBaseMapAndLines.setImageMatrix(matrix);
        this.firstScale = (float) width / (float) bitmapWith;
        matrix.preScale(this.firstScale, this.firstScale);
        originalPointView.setX((float) (originalPointView.getX() * scale));
        originalPointView.setY((float) (originalPointView.getY() * scale));
        moveMapPoints();
        move__tmpMapPoints();
    }
    public void my_showMap(Bitmap bitmap, int bitmapWith, int bitmapHeight) {
        myBaseMapAndLines.setImageBitmap(bitmap);
    }
    public void moveMapPoints() {
        for (int i = 0; i < mapPoints.size(); i++) {
            MyMapPointWithTitleView point = mapPoints.get(i);
            point.setFirstXShow((float) (point.getFirstX() * firstScale));
            point.setFirstYShow((float) (point.getFirstY() * firstScale));
        }
    }
    public void move__tmpMapPoints() {
        if(myMapPointWithTitleView_tmp!=null) {
            myMapPointWithTitleView_tmp.setFirstXShow((float) (myMapPointWithTitleView_tmp.getFirstX() * firstScale));
            myMapPointWithTitleView_tmp.setFirstYShow((float) (myMapPointWithTitleView_tmp.getFirstY() * firstScale));
        }
    }
    public void first_show_map_zoom(float scale)
    {
        moveMapPoints();
    }

    public void Refresh_show_get_new_map_picture( )
    {
        myBaseMapAndLines.setImageMatrix(myBaseMapAndLines.getImageMatrix());
        Matrix matrix = new Matrix();
        matrix.set(myBaseMapAndLines.getImageMatrix());
        float[] matrixValues = new float[9];
        matrix.getValues(matrixValues);
        originalPointView.setX((float) (0 * matrixValues[0] + matrixValues[2]));
        originalPointView.setY((float) (0 * matrixValues[4] + matrixValues[5]));
        for (int i = 0; i < mapPoints.size(); i++) {
            double scaleX = mapPoints.get(i).getFirstX() * matrixValues[0];
            double scaleY = mapPoints.get(i).getFirstY() * matrixValues[4];
            mapPoints.get(i).setFirstXShow((float) (scaleX + matrixValues[2]));
            mapPoints.get(i).setFirstYShow((float) (scaleY + matrixValues[5]));
        }
        if(myMapPointWithTitleView_tmp!=null) {
            double scaleX = myMapPointWithTitleView_tmp.getFirstX() * matrixValues[0];
            double scaleY = myMapPointWithTitleView_tmp.getFirstY() * matrixValues[4];
            myMapPointWithTitleView_tmp.setFirstXShow((float) (scaleX + matrixValues[2]));
            myMapPointWithTitleView_tmp.setFirstYShow((float) (scaleY + matrixValues[5]));

        }
        myBaseMapAndLines.invalidate();
    }
    public void setMapOnLongClickListener(MyMapViewOnLongClickListener mapOnLongClickListener) {
        this.mapOnLongClickListener = mapOnLongClickListener;
        this.setOnLongClickListener(this);
    }
    public MyMapViewOnLongClickListener getMapOnLongClickListener() {
        return mapOnLongClickListener;
    }

    public void get_marked_positionInfo_for_move_point(String pointTitle, double firstX, double firstY, float fingerX, float fingerY)
    {
        My_map.activity.marked_move_fingerX=(float)firstX*firstScale+originalPointView.getX();
        My_map.activity.marked_move_fingerY=(float)firstY*firstScale+originalPointView.getY() ;
        My_map.activity.marked_positionInfo_y_move=(My_map.activity.map_hight -firstY)*My_map.activity.resolution +My_map.activity.resolution_position_y;
        My_map.activity.marked_positionInfo_x_move=firstX *My_map.activity.resolution+My_map.activity.resolution_position_x;
    }

    @Override
    public boolean onLongClick(View v) {
        if (longPressTag) {
            float firstDownX = getFirstDownX();
            float firstDownY = getFirstDownY();
            float fingerX = firstDownX;
            float fingerY = firstDownY;
            float originalPointViewX = originalPointView.getX();
            float originalPointViewY = originalPointView.getY();
            float x = (fingerX - originalPointViewX) / firstScale;
            float y = (fingerY - originalPointViewY) / firstScale;
            My_map.activity.marked_LongClickdown_fingerX=fingerX;
            My_map.activity.marked_LongClickdown_fingerY=fingerY;
            marked_mapX = (My_map.activity.marked_LongClickdown_fingerX - originalPointView.getX()) / firstScale;
            marked_mapY = (My_map.activity.marked_LongClickdown_fingerY - originalPointView.getY()) / firstScale;
            My_map.activity.marked_positionInfo_y=(My_map.activity.map_hight -marked_mapY)*My_map.activity.resolution +My_map.activity.resolution_position_y;
            My_map.activity.marked_positionInfo_x=marked_mapX *My_map.activity.resolution+My_map.activity.resolution_position_x;
            this.mapOnLongClickListener.myMapViewOnLongClick(x, y,fingerX,fingerY);
            return true;
        }
        return false;
    }

    public float getFirstDownX() {
        return firstDownX;
    }
    public void setFirstDownX(float firstDownX) {
        this.firstDownX = firstDownX;
    }
    public float getFirstDownY() {
        return firstDownY;
    }
    public void setFirstDownY(float firstDownY) {
        this.firstDownY = firstDownY;
    }
    public interface MyMapViewOnLongClickListener {
        void myMapViewOnLongClick(float downX, float downY,float fingerX, float fingerY);
    }
    private class MyTouchListener implements OnTouchListener {
        private int mode = 0;
        private static final int MODE_DRAG = 1;
        private static final int MODE_ZOOM = 2;
        private PointF startPoint = new PointF();
        private Matrix matrix = new Matrix();
        private Matrix currentMatrix = new Matrix();
        private float startDis;
        private PointF midPoint;
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    mode = MODE_DRAG;
                    currentMatrix.set(myBaseMapAndLines.getImageMatrix());
                    startPoint.set(event.getX(), event.getY());
                    longPressTag = true;
                    downTime = System.currentTimeMillis();
                    setFirstDownX(event.getX());
                    setFirstDownY(event.getY());
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == MODE_DRAG) {
                        float dx = event.getX() - startPoint.x;
                        float dy = event.getY() - startPoint.y;
                        matrix.set(currentMatrix);
                        matrix.postTranslate(dx, dy);
                        float offset = (float) Math.sqrt(dx * dx + dy * dy);
                        longPressTag = offset < 10 ? true : false;
                    }
                    else if (mode == MODE_ZOOM) {
                        float endDis = distance(event);
                        if (endDis > 10f) {
                            float scale = endDis / startDis;
                            matrix.set(currentMatrix);
                            matrix.postScale(scale, scale, midPoint.x, midPoint.y);
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    longPressTag = System.currentTimeMillis() - downTime > 2000 ? true : false;
                case MotionEvent.ACTION_POINTER_UP:
                    mode = 0;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    longPressTag = false;
                    mode = MODE_ZOOM;
                    startDis = distance(event);
                    if (startDis > 10f) {
                        midPoint = mid(event);
                        currentMatrix.set(myBaseMapAndLines.getImageMatrix());
                    }
                    break;
            }
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_MOVE:
                    myBaseMapAndLines.setImageMatrix(matrix);
                    float[] matrixValues = new float[9];
                    matrix.getValues(matrixValues);
                    originalPointView.setX((float) (0 * matrixValues[0] + matrixValues[2]));
                    originalPointView.setY((float) (0 * matrixValues[4] + matrixValues[5]));
                    firstScale = matrixValues[0];
                    marked_mapX = (My_map.activity.marked_LongClickdown_fingerX - originalPointView.getX()) / firstScale;
                    marked_mapY = (My_map.activity.marked_LongClickdown_fingerY - originalPointView.getY()) / firstScale;
                    My_map.activity.marked_positionInfo_y=(My_map.activity.map_hight -marked_mapY)*My_map.activity.resolution +My_map.activity.resolution_position_y;
                    My_map.activity.marked_positionInfo_x=marked_mapX *My_map.activity.resolution+My_map.activity.resolution_position_x;
                    float mapX = (My_map.activity.marked_move_fingerX - originalPointView.getX()) / firstScale;
                    float mapY = (My_map.activity.marked_move_fingerY - originalPointView.getY()) / firstScale;
                    My_map.activity.marked_positionInfo_y_move=(My_map.activity.map_hight -mapY)*My_map.activity.resolution +My_map.activity.resolution_position_y;
                    My_map.activity.marked_positionInfo_x_move=mapX *My_map.activity.resolution+My_map.activity.resolution_position_x;
                    for (int i = 0; i < mapPoints.size(); i++) {
                        double scaleX = mapPoints.get(i).getFirstX() * matrixValues[0];
                        double scaleY = mapPoints.get(i).getFirstY() * matrixValues[4];
                        mapPoints.get(i).setFirstXShow((float) (scaleX + matrixValues[2]));
                        mapPoints.get(i).setFirstYShow((float) (scaleY + matrixValues[5]));
                    }
                    if(myMapPointWithTitleView_tmp!=null) {
                        double scaleX = myMapPointWithTitleView_tmp.getFirstX() * matrixValues[0];
                        double scaleY = myMapPointWithTitleView_tmp.getFirstY() * matrixValues[4];
                        myMapPointWithTitleView_tmp.setFirstXShow((float) (scaleX + matrixValues[2]));
                        myMapPointWithTitleView_tmp.setFirstYShow((float) (scaleY + matrixValues[5]));

                    }
                    myBaseMapAndLines.invalidate();
                    getParent().requestDisallowInterceptTouchEvent(true);
                    break;
            }
            if (getMapOnLongClickListener() != null) {
                return false;
            }
            return true;
        }
        private float distance(MotionEvent event) {
            float dx = event.getX(1) - event.getX(0);
            float dy = event.getY(1) - event.getY(0);
            return (float) Math.sqrt(dx * dx + dy * dy);
        }
        private PointF mid(MotionEvent event) {
            float midX = (event.getX(1) + event.getX(0)) / 2;
            float midY = (event.getY(1) + event.getY(0)) / 2;
            return new PointF(midX, midY);
        }
    }
}
